// client.cpp
#define _WIN32_DCOM
#include <olectl.h>
#include <conio.h>
#include <iostream.h>
#include "Component\component.h"

class CSink : public IOutGoing
{
public:
	// IUnknown
	ULONG __stdcall AddRef();
	ULONG __stdcall Release();
	HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);

	// IOutGoing
	HRESULT __stdcall GotMessage(int Message);

	CSink() : m_cRef(0) {  }
	~CSink() { }

private:
	long m_cRef;
};

ULONG CSink::AddRef()
{
	return ++m_cRef;
}

ULONG CSink::Release()
{
	if(--m_cRef != 0)
		return m_cRef;
	delete this;
	return 0;
}

HRESULT CSink::QueryInterface(REFIID riid, void** ppv)
{
	if(riid == IID_IUnknown)
	{
		*ppv = (IUnknown*)this;
	}
	else if(riid == IID_IOutGoing)
	{
		cout << "Component: CInsideCOM::QueryInterface() for IOutGoing" << endl;
		*ppv = (IOutGoing*)this;
	}
	else 
	{
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	AddRef();
	return S_OK;
}

HRESULT CSink::GotMessage(int Message)
{
	if(Message == (int)'b' || Message == (int)'B')
		PlaySound("BrockschmidtQuack", NULL, SND_RESOURCE|SND_ASYNC);
	cout << "CSink::GotMessage is " << (char)Message << endl;
	return S_OK;
}

void main()
{
	cout << "Client: Calling CoInitialize()" << endl;
	CoInitializeEx(NULL, COINIT_MULTITHREADED);
	
	IUnknown* pUnknown;
	cout << "Client: Calling CoCreateInstance() " << endl;
	CoCreateInstance(CLSID_InsideCOM, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown);

	IConnectionPointContainer* pConnectionPointContainer;
	HRESULT hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
	if(FAILED(hr))
		cout << "Not a connectable object, going to crash now" << endl;

	IEnumConnectionPoints* pEnumConnectionPoints;
	IEnumConnectionPoints* pEnumConnectionPoints2;
	hr = pConnectionPointContainer->EnumConnectionPoints(&pEnumConnectionPoints);

	ULONG num_fetched;
	IConnectionPoint* pConnectionPoint;
	hr = pEnumConnectionPoints->Clone(&pEnumConnectionPoints2);
	hr = pEnumConnectionPoints2->Next(1, &pConnectionPoint, &num_fetched);
	cout << "Next hr = " << hr << " num_fetched = " << num_fetched << endl;
	pEnumConnectionPoints->Release();
	pEnumConnectionPoints2->Release();

	IID my_iid;
	pConnectionPoint->GetConnectionInterface(&my_iid);

	char buffer[39];
	OLECHAR ppsz[39];
	StringFromGUID2(my_iid, ppsz, 39);
	WideCharToMultiByte(CP_ACP, 0, ppsz, 39, buffer, 39, NULL, NULL);
	cout << "IID: " << buffer << endl;

	IConnectionPointContainer* CPC;
	pConnectionPoint->GetConnectionPointContainer(&CPC);
	if(CPC == pConnectionPointContainer)
		cout << " THEY EQUAL " << endl;
	CPC->Release();

//	IConnectionPoint* pConnectionPoint;
//	hr = pConnectionPointContainer->FindConnectionPoint(IID_IOutGoing, &pConnectionPoint);
//	cout << "FindConnectionPoint returns " << hr << " pConnectionPoint = " << pConnectionPoint << endl;

	CSink* mySink = new CSink;
	DWORD dwCookie;
	pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie);
	cout << "CLIENT CALLED ADVISE" << hr << endl;

	IEnumConnections* pEnumConnections;
	pConnectionPoint->EnumConnections(&pEnumConnections);
	CONNECTDATA my_cd;
	ULONG dd;
	pEnumConnections->Next(1, &my_cd, &dd);
	cout << "MY COOKIE = " << my_cd.dwCookie << endl;
	cout << "MY COOKIE2 = " << dwCookie << endl;
	pEnumConnections->Release();

	cout << "Press any key to exit" << endl;
	_getch();

	pConnectionPoint->Unadvise(dwCookie);
	pConnectionPoint->Release();
	pConnectionPointContainer->Release();

	cout << "Client: Calling Release() for pUnknown" << endl;
	hr = pUnknown->Release();

	cout << "Client: Calling CoUninitialize()" << endl;
	CoUninitialize();
}